如何决定用组合还是继承

组合优于继承,多用组合,少用继承

继承

面向对象四个特性之一,用来表示is-a的关系,解决代码复用的问题

不足

  • 继承层次过深,过复杂。
  • 不利于后期需求的变更,影响代码的可扩展性。
  • 代码的可读性变差,需要弄清楚某个类需要哪些方法,必须阅读所有父类的代码。
  • 破坏了类的封装性,将父类的实现细节暴露给子类,子类的实现依赖父类的子线,子类和父类高度耦合,一旦父类变化就会影响子类。

案例

鸟的继承体系

  • 有会飞的鸟也有不会飞的鸟,,当父类定义一个fly()的方法,则子类都会拥有飞行的功能,对于鸵鸟,可以重写fly()方法,抛出异常即可,这样虽然可行,但是不够优美,违反最少知识原则,暴露了不该暴露的接口给外部。
  • 后序考虑鸟会不会叫、鸟下不下单等属性,那么继承体系就非常庞大了。

组合

有什么手段可以代替继承,并且避免继承的不足–组合+接口+委托

  • 多态(接口),运用接口可以实现继承体系中的多态的作用。接口表示某种行为特征,Flyable(可以飞的行为),EggLayable(可下蛋的行为)

  • 代码复用(组合+委托),由于每一个会飞的鸟都要去实现Flyable,所有我们可以定义一个实现类,然后通过组合和委托的形式,将Flyable的实现类组合进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface Flyable{
void fly();
}

public class FlyAbility implement Flyable{
public void fly(){
....
}
}

public class Ostrish implements Tweetable,EggLayable{
//组合
private TweetAbility tweetAbility = new TweetAbility();

public void tweet(){
//委托
tweetAbility.tweet();
}
}

如何决定选择组合还是继承

组合的不足

  • 更细粒度的类划分,更多的类和接口
  • 增加代码的复杂程度和维护成本

继承的不足

  • 继承层次过深灰降低代码的扩展性
  • 代码可读性差

继承的条件

  • 类之间的继承结构稳定(不会轻易改变)
  • 继承层次浅(2-3层)
  • 继承关系简单

继承和组合在设计模式中的应用

  • 继承(模板模式)
  • 组合(装饰器模式、策略模式、组合模式)

多用组合,少用继承并不是绝对的,需要具体情况具体分析,控制好他们的副作用,发挥他们各自的优势。